/*******************************************************************************
 * This file is part of blueprint4j www.blueprint4j.org.
 * 
 *     blueprint4j is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     blueprint4j is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Lesser General Public License for more details.
 * 
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with blueprint4j. If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package blueprint4j.gui.db;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.sql.SQLException;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import blueprint4j.db.DBConnection;
import blueprint4j.db.DataException;
import blueprint4j.db.Entity;
import blueprint4j.gui.Binder;
import blueprint4j.gui.DataPanelInterface;
import blueprint4j.gui.Gui;
import blueprint4j.gui.JTitleLabel;
import blueprint4j.gui.SaveableComponent;
import blueprint4j.utils.BindException;
import blueprint4j.utils.Log;
import blueprint4j.utils.Settings;


public class EntityEditor extends JPanel implements EntityPanelSelectionListner,ChangeListener,Saveable,SaveableComponent {
	private static final long serialVersionUID = 1L;
	
	static final public String BOTTOM=BorderLayout.SOUTH;
    static final public String RIGHT=BorderLayout.EAST;
    static final public String TOP=BorderLayout.NORTH;
    static final public String LEFT=BorderLayout.WEST;
    
    //private JPanel main = new JPanel();
    private boolean panel_build [] = null;
    private DataPanelInterface[] panels;
    private Entity current_entity = null;
    private EntityPanel list;
    private EntityWizard entity_wizard = null;
    private DBConnection connection=null;
    private Binder binder,parent_binder = null;
    private JSplitPane splitPane = null;
    private JTabbedPane tabs = new JTabbedPane(JTabbedPane.LEFT,JTabbedPane.SCROLL_TAB_LAYOUT);
    private JPanel center_panel = new JPanel(new BorderLayout());
    private JLabel title_label=new JTitleLabel();
    private int last_active_tab = 0;
    private boolean EXCEPTION_OCCURRED_DONOT_SAVE = false;
    private String list_location=LEFT;
    private Dimension preferred_size= null;
    private String other_where = null;
    static public int default_tab_placement=SwingConstants.LEFT;
    private int tab_placement=default_tab_placement;
    
    private EntityEditorSavedEventListner saved_listener = null;
    
    //private VectorEntityPanelSelectionListner local_selectionlistener = new VectorEntityPanelSelectionListner();
    
    public EntityEditor() {}
    
    public void setEntityEditorSavedEventListner(EntityEditorSavedEventListner saved_listener) {
        this.saved_listener = saved_listener;
    }
    
    public EntityEditor(DBConnection connection,String title)
    throws DataException, SQLException {
        this(connection);
        setTitle(title);
    }
    
    public EntityEditor(DBConnection connection)
    throws DataException, SQLException {
        super(new BorderLayout());
        Gui.addEnter4FocusShift(this);
        this.connection = connection;
        connection.setAutoCommit(true);
    }
    
    public EntityPanel getEntityPanel() {
        return list;
    }
    
    public void removeReferences() {
        removeAll();
        if (list != null) {
            list.removeSelectionListner(this);
            list.setEntityWizard(null);
        }
    }
    
    public void setDetails(Entity p_entity, EntityPanelFieldBinder[] p_binders, DataPanelInterface[] p_panels)
    throws DataException, SQLException,BindException {
        setDetails(p_entity, p_binders, p_panels, Settings.getInt("gui.entity_panel.default_max_items", 200));
    }
    
    public void setDetails(Entity p_entity, EntityPanelFieldBinder[] p_binders, DataPanelInterface[] p_panels, int max)
    throws DataException, SQLException,BindException {
        setDetails(p_entity,p_binders,p_panels,max,null,null);
    }
    
    public void setDetails(Entity p_entity, EntityPanelFieldBinder[] p_binders, DataPanelInterface[] p_panels, int max,JButton extra_btn[],EntityPanelSelectionListner p_extra_listeners[])
    throws DataException, SQLException,BindException {
        removeReferences();
        panels = p_panels;
        panel_build = new boolean[p_panels.length];
        for (int i = 0;i < panel_build.length;i++) {
            panel_build[i] = false;
        }
        list = new EntityPanel(p_entity, p_binders, max,extra_btn,p_extra_listeners,other_where);
        list.setEntityEditor(this);
        list.setEntityWizard(entity_wizard);
        
        // DEFAULT THE LIST SIZE TO NAME FIELD WIDTH BY 300
        int width = 0;
        for (int i =0;i < p_binders.length;i++) {
            width += p_binders[i].getColumnWidth();
        }
        if (splitPane==null){
	        if (EntityEditor.TOP.equals(list_location) || EntityEditor.BOTTOM.equals(list_location)) {
	            splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,list, center_panel);
	        } else {
	            splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,list, center_panel);
	        }
	        splitPane.setOneTouchExpandable(true);
	        if (preferred_size != null) {
	            if (EntityEditor.TOP.equals(list_location) || EntityEditor.BOTTOM.equals(list_location)) {
	                splitPane.setDividerLocation((int)preferred_size.getHeight());
	            } else {
	                splitPane.setDividerLocation((int)preferred_size.getWidth());
	            }
	        }
	        build();
        }
        list.addSelectionListner(this);
    }
    

    public void setEntityWizard(EntityWizard entity_wizard) {
        this.entity_wizard = entity_wizard;
        if (list !=null) {
            list.setEntityWizard(entity_wizard);
        }
    }
    
    public void setListPreferredSize(Dimension d){
        preferred_size = d;
        if (splitPane != null) {
            if (list_location == null || (EntityEditor.TOP.equals(list_location) || EntityEditor.BOTTOM.equals(list_location))) {
                splitPane.setDividerLocation((int)d.getHeight());
            } else {
                splitPane.setDividerLocation((int)d.getWidth());
            }
        }        
    }
    
    public void setTitle(String title){
        title_label.setText(title);
    }
    
    public void addNewEventListner(EntityPanelNewEventListner listner) {
    	if (list==null){
    		return;
    	}
        list.addNewEventListner(listner);
    }
    
    public void removeNewEventListner(EntityPanelNewEventListner listner) {
    	if (list==null){
    		return;
    	}
        list.removeNewEventListner(listner);
    }
    
    public void addSelectionListner(EntityPanelSelectionListner listner) {
    	if (list==null){
    		return;
    	}
        list.addSelectionListner(listner);
    }
    
    public void removeSelectionListner(EntityPanelSelectionListner listner) {
    	if (list==null){
    		return;
    	}
        list.removeSelectionListner(listner);
    }
    
    public String getOtherWhere() {
    	if (list==null){
    		return other_where;
    	}
        return list.getOtherWhere();
    }
    
    public void setOtherWhere(String p_other_where)
    throws SQLException, DataException, BindException{
        if (list!=null){
            list.setOtherWhere(p_other_where);
        }
        other_where=p_other_where;
    }
    
    public void setCompleteWhere(String complete_where)
    throws BindException {
        if (list != null) {
            list.setCompleteWhere(complete_where);
        }
    }
    
    public Entity getSelectedEntity() {
        return list.getSelectedEntity();
    }
    
    public EntityPanelDeleteAuthorizer getAuthorizer() {
        return list.getAuthorizer();
    }
    
    public void setAuthorizer(EntityPanelDeleteAuthorizer p_authorizer) {
        list.setAuthorizer(p_authorizer);
    }
    
    public void enableAdd(boolean enable){
        list.enableAdd(enable);
    }
    
    public void enableImport(boolean enable){
        list.enableImport(enable);
    }
    
    public void enableExport(boolean enable){
        list.enableExport(enable);
    }
    
    public void enableSearch(boolean enable){
        list.enableSearch(enable);
    }
    
    public void enableDelete(boolean enable){
        list.enableDelete(enable);
    }
    
    protected DBConnection getConnection() {
        return connection;
    }
    
    private void build() {
        //add(list, list_location);
        //add(center_panel, BorderLayout.CENTER);
    	//removeAll();
        add(splitPane);
        selection(null);
    }
    
    public void setListLocation(String border_layout_position){
        list_location=border_layout_position;
    }
    
        /*
        public void setDetailsPosition(String position){
                if (position==BOTTOM){
                        add(list,BorderLayout.NORTH);
                }else{
                        add(list,BorderLayout.WEST);
                }
}*/
    
    protected void createNewBinderInstance() {
        if (parent_binder != null) {
            binder = (Binder) parent_binder.clone();
        } else {
            binder = new Binder();
        }
    }
    
    public Binder getBinder() {
        return binder;
    }
    
    public void setParentBinder(Binder parent_binder) {
        this.parent_binder = parent_binder;
    }
    
    private boolean in_selection=false;
    public void selection(Entity entity) {
    	if (in_selection){
    		return;
    	}
    	in_selection=true;
        //createNewBinderInstance();
        current_entity = entity;
        if (current_entity !=null) {
            current_entity.setNewConnection(connection);
        }
        tabs.removeChangeListener(this);
        tabs.removeAll();
        tabs=new JTabbedPane(JTabbedPane.LEFT,JTabbedPane.SCROLL_TAB_LAYOUT);
        tabs.setTabPlacement(tab_placement);
        tabs.setFocusable(false);
        
        for (int i = 0;i < panel_build.length;i++) {
            panel_build[i] = false;
        }
        createNewBinderInstance();
        binder.addBinderListner(list);
        if (current_entity != null) {
            try {
                // Build controls and add tabs
                panels[last_active_tab].setBinderBindable(binder,current_entity);
                panel_build[last_active_tab] = true;
                for (int t = 0;t < panels.length;t++) {
                    tabs.add(panels[t].getComponent(), panels[t].getName());
                }
                if (current_entity.isLoaded()) {
                    binder.reload();
                }
                tabs.setSelectedIndex(last_active_tab);
                tabs.addChangeListener(this);
            } catch (BindException be) {
                Log.debug.out( be);
                try {
                    refreshList();
                } catch (Exception exception) {
                    Log.debug.out( exception);
                }
            } catch (Exception ioe) {
                Log.debug.out( ioe);
            }
        }
        center_panel.removeAll();
        center_panel.add(title_label,BorderLayout.NORTH);
        //if (tabs.getTabCount()!=1){
            center_panel.add(tabs, BorderLayout.CENTER);
        //}else{
        	//center_panel.add(panels[0].getComponent(), BorderLayout.CENTER);
            //panels[0].activated();
            //stateChanged(null);
        //}
        in_selection=false;
        revalidate();
    }
    
    public static void setDefaultTabPlacement(int tab_placement){
    	default_tab_placement=tab_placement;
    }
    
    public void setTabPlacement(int tab_placement){
    	if (tabs!=null){
    		tabs.setTabPlacement(tab_placement);		
    	}
    	this.tab_placement=tab_placement;
    }
    
    public void refreshList() {
        list.actionRefresh();
    }
    
    public JPanel getPanel() {
        return null;
    }
    
    public String getName() {
        return title_label.getText();
    }
    
    // activate the last active data panel
    public void activate() {
        if (tabs.getSelectedIndex() > -1) {
            panels[tabs.getSelectedIndex()].activated();
        }
    }
    
    // deactivate the last active data panel
    public void deactivate() {
        if (tabs.getSelectedIndex() > -1) {
            panels[tabs.getSelectedIndex()].deactivated();
        }
    }
    
    public boolean save() {
        try {
            try {
                if (binder != null) {
                    binder.save();
                    if (saved_listener != null) {
                        saved_listener.editorSaved();
                    }
                }
                return true;
            } catch (DataException.ValidationException ve) {
                for (int i = 0;i < panels.length;i++) {
                    if (panels[i].doesPanelContain(ve.field)) {
                        EXCEPTION_OCCURRED_DONOT_SAVE = true;
                        tabs.setSelectedIndex(i);
                        EXCEPTION_OCCURRED_DONOT_SAVE = false;
                        break;
                    }
                }
                throw ve;
            }
        } catch (Exception exception) {
            Log.debug.out(exception);
            JOptionPane.showMessageDialog(this,exception.getMessage());
        }
        return false;
    }
    
    public void removeNotify(){
        super.removeNotify();
        try {
            if (binder != null) {
                binder.save();
            }
        } catch (Exception exception) {
            JOptionPane.showMessageDialog(this,exception.getMessage());
            Log.debug.out(exception);
        }
    }
    
    public void stateChanged(ChangeEvent e) {
        if (EXCEPTION_OCCURRED_DONOT_SAVE) {
            Log.trace.out("EXCEPTION_OCCURRED_DONOT_SAVE");
            return;
        }
        try {
            if (tabs.getSelectedIndex() >= 0) {
                save();
                panels[last_active_tab].deactivated();
                panels[tabs.getSelectedIndex()].activated();
                last_active_tab = tabs.getSelectedIndex();
                // build that tab
                if (!panel_build[last_active_tab] && current_entity != null) {
                    panels[last_active_tab].setBinderBindable(binder,current_entity);
                    panel_build[last_active_tab]=true;
                    binder.reload();
                }
                
                // TODO would be nice to figure out if we could skip this refresh it will be a little annoying in responsiveness of the UI
                if (panels[tabs.getSelectedIndex()] instanceof Editor){
                	((Editor)panels[tabs.getSelectedIndex()]).refreshList();
                }
            }
        } catch (Exception exception) {
            JOptionPane.showMessageDialog(this,exception.getMessage());
            Log.debug.out(exception);
            tabs.setSelectedIndex(last_active_tab);
        }
    }
    
    public void setActiveDataPanel(DataPanelInterface panel) {
        for (int i = 0;i < panels.length && i < tabs.getTabCount();i++) {
            if (panels[i] == panel) {
                tabs.setSelectedIndex(i);
            }
        }
    }
    
    public JComponent getComponent() {
        return this;
    }
    
}

